package com.example.aop;

import com.example.pojo.OperateLog;
import com.example.mapper.OperateLogMapper;
import com.example.utils.CurrentHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

@Slf4j
@Aspect
@Component
public class OperateLogAspect {

    @Autowired
    private OperateLogMapper operateLogMapper;

    @Around("@annotation(com.example.anno.Log)")
    public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable {

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        // 执行目标方法
        Object returnValue = joinPoint.proceed();

        // 记录结束时间
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;

        // 构造操作日志对象
        /**
         * 创建并填充操作日志对象。
         * 该代码块用于记录方法的执行信息，包括操作人ID、操作时间、类名、方法名、方法参数、返回值以及执行耗时。
         *
         * 代码块逻辑：
         * 1. 创建一个新的OperateLog对象。
         * 2. 设置操作人ID为当前用户的ID。
         * 3. 设置操作时间为当前时间。
         * 4. 设置类名为目标对象的类名。
         * 5. 设置方法名为当前执行的方法名。
         * 6. 设置方法参数为当前方法的参数列表的字符串表示。
         * 7. 设置返回值为当前方法的返回值，如果返回值为空则设置为"void"。
         * 8. 设置执行耗时为方法的执行时间。
         */
        OperateLog operateLog = new OperateLog();
        operateLog.setOperateEmpId(getCurrentEmpId());
        operateLog.setOperateTime(LocalDateTime.now());
        operateLog.setClassName(joinPoint.getTarget().getClass().getName());
        operateLog.setMethodName(joinPoint.getSignature().getName());
        operateLog.setMethodParams(Arrays.toString(joinPoint.getArgs()));
        operateLog.setReturnValue(returnValue != null ? returnValue.toString() : "void");
        operateLog.setCostTime(costTime);

        // 保存操作日志
        log.info("操作日志：{}", operateLog);
        operateLogMapper.insert(operateLog);

        return returnValue;
    }

    // 模拟获取当前操作人ID的方法
    private Integer getCurrentEmpId() {
        // 获取当前线程的holder中的员工id
        return CurrentHolder.getCurrentId();
    }
}
